package com.project.springboot.config;

import com.google.common.util.concurrent.ThreadFactoryBuilder;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.scheduling.annotation.AsyncConfigurer;
import org.springframework.scheduling.annotation.EnableAsync;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;

import java.util.concurrent.Executor;
import java.util.concurrent.ThreadPoolExecutor;

/**
 * description: 异步任务配置类
 * @author 朱正磊
 * @date 2025-06-05 14:44:07
 */
@EnableAsync
@Configuration
public class AsyncConfig implements AsyncConfigurer {

    /**
     * description: 创建异步线程池对象
     * @author 朱正磊
     * @date 2025-06-16 18:49:59
     * @return 返回线程池对象
     */
    @Override
    @Bean(name = "asyncTaskExecutor")
    public Executor getAsyncExecutor() {
        ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
        // 核心线程数
        executor.setCorePoolSize(5);
        // 最大线程数
        executor.setMaxPoolSize(10);
        // 空闲存活时间（秒），设置为30秒
        executor.setKeepAliveSeconds(30);
        // 工作队列容量
        executor.setQueueCapacity(100);

        // 线程名前缀
        // 如果手动设置了ThreadFactory（如通过ThreadFactoryBuilder），则setThreadNamePrefix方法的设置会被完全忽略，线程名称由ThreadFactory决定
        // 如果未设置ThreadFactory，则setThreadNamePrefix会生效，线程池会使用默认的线程工厂，并将前缀应用到线程名称中
        // setThreadNamePrefix：该方法会在内部创建一个默认的ThreadFactory，并将前缀应用到线程名称中（例如 prefix-1）。但如果手动设置了ThreadFactory，这个默认工厂不会被创建，前缀也就无效了
        // executor.setThreadNamePrefix("xxx");

        // 线程工厂，非守护线程，即用户线程，同时设置线程命名
        // setThreadFactory：手动设置ThreadFactory后，线程池会完全使用该工厂创建线程，线程名称由工厂的实现决定（如ThreadFactoryBuilder中的setNameFormat）
        executor.setThreadFactory(new ThreadFactoryBuilder().setNameFormat("async-task-%d").setDaemon(false).build());

        // 任务拒绝策略，将任务返回给调用者线程执行，减缓新任务提交速度，避免系统过载
        executor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy());

        // 无需手动调用initialize()，Spring会自动处理
        // executor.initialize();

        return executor;
    }

}
